Template System and Nunjucks Usage

**Referenced Files in This Document** - [base.njk](file://src/_includes/layouts/base.njk) - [iaa-base.njk](file://src/_includes/layouts/iaa-base.njk) - [knowledge.njk](file://src/_includes/layouts/knowledge.njk) - [case-study-card.njk](file://src/_includes/macros/case-study-card.njk) - [client-marquee.njk](file://src/_includes/macros/client-marquee.njk) - [testimonial-card.njk](file://src/_includes/macros/testimonial-card.njk) - [newsletter-signup.njk](file://src/_includes/macros/newsletter-signup.njk) - [cta-section.njk](file://src/_includes/macros/cta-section.njk) - [team-flip-card.njk](file://src/_includes/macros/team-flip-card.njk) - [news-article-card.njk](file://src/_includes/macros/news-article-card.njk) - [service-capability-card.njk](file://src/_includes/macros/service-capability-card.njk) - [index.njk](file://src/index.njk) - [about.njk](file://src/about.njk) - [cases.njk](file://src/cases.njk) - [news.njk](file://src/news.njk) - [media-management.njk](file://src/services/media-management.njk)

Table of Contents

  1. Introduction
  2. Project Structure
  3. Core Components
  4. Architecture Overview
  5. Detailed Component Analysis
  6. Dependency Analysis
  7. Performance Considerations
  8. Troubleshooting Guide
  9. Conclusion
  10. Appendices

Introduction

This document explains the Nunjucks-based templating system used in Eleventy for building the website. It focuses on:

  • Base layout structure and inheritance patterns
  • Reusable macros for components such as case-study-card, client-marquee, testimonial-card, and newsletter-signup
  • Template syntax, variable interpolation, conditionals, loops, filters, and imports
  • How layouts, includes, and page-specific templates relate
  • Practical examples for creating new macros, extending layouts, and implementing template inheritance
  • Template compilation process and debugging techniques

Project Structure

Eleventy uses front matter to declare a layout per page, and Nunjucks macros to encapsulate reusable UI components. Layouts define the shell; pages provide content; macros encapsulate markup and logic.

graph TB
subgraph "Layouts"
L_base["layouts/base.njk"]
L_iaa["layouts/iaa-base.njk"]
L_knowledge["layouts/knowledge.njk"]
end
subgraph "Macros"
M_case["macros/case-study-card.njk"]
M_marquee["macros/client-marquee.njk"]
M_testimonial["macros/testimonial-card.njk"]
M_newsletter["macros/newsletter-signup.njk"]
M_cta["macros/cta-section.njk"]
M_team["macros/team-flip-card.njk"]
M_news_card["macros/news-article-card.njk"]
M_service_card["macros/service-capability-card.njk"]
end
subgraph "Pages"
P_home["index.njk"]
P_about["about.njk"]
P_cases["cases.njk"]
P_news["news.njk"]
P_service["services/media-management.njk"]
end
P_home --> L_base
P_about --> L_base
P_cases --> L_base
P_news --> L_base
P_service --> L_base
L_knowledge --> L_base
P_home -. imports .-> M_marquee
P_home -. imports .-> M_service_card
P_home -. imports .-> M_team
P_home -. imports .-> M_news_card
P_home -. imports .-> M_testimonial
P_home -. imports .-> M_cta
P_cases -. imports .-> M_case
P_cases -. imports .-> M_cta
P_news -. imports .-> M_news_card
P_news -. imports .-> M_newsletter
P_news -. imports .-> M_cta

Diagram sources

  • [base.njk](file://src/_includes/layouts/base.njk)
  • [iaa-base.njk](file://src/_includes/layouts/iaa-base.njk)
  • [knowledge.njk](file://src/_includes/layouts/knowledge.njk)
  • [case-study-card.njk](file://src/_includes/macros/case-study-card.njk)
  • [client-marquee.njk](file://src/_includes/macros/client-marquee.njk)
  • [testimonial-card.njk](file://src/_includes/macros/testimonial-card.njk)
  • [newsletter-signup.njk](file://src/_includes/macros/newsletter-signup.njk)
  • [cta-section.njk](file://src/_includes/macros/cta-section.njk)
  • [team-flip-card.njk](file://src/_includes/macros/team-flip-card.njk)
  • [news-article-card.njk](file://src/_includes/macros/news-article-card.njk)
  • [service-capability-card.njk](file://src/_includes/macros/service-capability-card.njk)
  • [index.njk](file://src/index.njk)
  • [about.njk](file://src/about.njk)
  • [cases.njk](file://src/cases.njk)
  • [news.njk](file://src/news.njk)
  • [media-management.njk](file://src/services/media-management.njk)

Section sources

  • [base.njk](file://src/_includes/layouts/base.njk)
  • [index.njk](file://src/index.njk)
  • [about.njk](file://src/about.njk)
  • [cases.njk](file://src/cases.njk)
  • [news.njk](file://src/news.njk)
  • [media-management.njk](file://src/services/media-management.njk)

Core Components

  • Base layout: Provides the HTML skeleton, meta tags, navigation, main content placeholder, footer, and scripts. Pages declare layout: base.njk in front matter to inherit this structure.
  • Knowledge layout: Extends the base layout for article-like content with breadcrumbs, metadata, and a clean article body.
  • IAA base layout: A specialized layout for the alliance subdomain with distinct branding and navigation.
  • Macros: Encapsulate reusable components with parameters and optional defaults. Pages import macros and render them with data.

Key template features demonstrated:

  • Variable interpolation via double curly braces
  • Filters (e.g., safe, replace, dateFormat, readingTime)
  • Control structures (conditionals and loops)
  • Macro imports and invocations
  • Front matter for layout selection and page metadata

Section sources

  • [base.njk](file://src/_includes/layouts/base.njk)
  • [knowledge.njk](file://src/_includes/layouts/knowledge.njk)
  • [iaa-base.njk](file://src/_includes/layouts/iaa-base.njk)
  • [case-study-card.njk](file://src/_includes/macros/case-study-card.njk)
  • [client-marquee.njk](file://src/_includes/macros/client-marquee.njk)
  • [testimonial-card.njk](file://src/_includes/macros/testimonial-card.njk)
  • [newsletter-signup.njk](file://src/_includes/macros/newsletter-signup.njk)
  • [cta-section.njk](file://src/_includes/macros/cta-section.njk)
  • [team-flip-card.njk](file://src/_includes/macros/team-flip-card.njk)
  • [news-article-card.njk](file://src/_includes/macros/news-article-card.njk)
  • [service-capability-card.njk](file://src/_includes/macros/service-capability-card.njk)

Architecture Overview

The templating pipeline:

  • Eleventy reads a page (e.g., index.njk) and parses its front matter.
  • If layout is declared, Eleventy renders the page content into the named layout.
  • The layout’s {{ content | safe }} placeholder receives the page content.
  • Macros are imported inside pages and invoked with data from collections or data files.
sequenceDiagram
participant E as "Eleventy"
participant Page as "Page Template (e.g., index.njk)"
participant Macro as "Macro (e.g., client-marquee.njk)"
participant Layout as "Layout (e.g., base.njk)"
E->>Page : Parse front matter and template
Page->>Macro : Import and call macro with parameters
Macro-->>Page : Rendered HTML fragment
Page->>Layout : Render with content injected at {{ content | safe }}
Layout-->>E : Final HTML

Diagram sources

  • [index.njk](file://src/index.njk)
  • [client-marquee.njk](file://src/_includes/macros/client-marquee.njk)
  • [base.njk](file://src/_includes/layouts/base.njk)

Section sources

  • [index.njk](file://src/index.njk)
  • [base.njk](file://src/_includes/layouts/base.njk)

Detailed Component Analysis

Base Layout and Inheritance

  • The base layout defines the global HTML structure, SEO metadata, navigation, main content area, footer, and scripts.
  • Pages set layout: base.njk in front matter to inherit the base shell.
  • The knowledge layout extends the base layout for article pages, adding breadcrumbs, metadata, and a dedicated article body.
classDiagram
class BaseLayout {
+HTML head and meta
+Navigation
+Main content placeholder
+Footer
+Scripts
}
class KnowledgeLayout {
+Extends BaseLayout
+Breadcrumbs
+Metadata
+Article body
}
KnowledgeLayout --> BaseLayout : "extends"

Diagram sources

  • [base.njk](file://src/_includes/layouts/base.njk)
  • [knowledge.njk](file://src/_includes/layouts/knowledge.njk)

Section sources

  • [base.njk](file://src/_includes/layouts/base.njk)
  • [knowledge.njk](file://src/_includes/layouts/knowledge.njk)

Macro: client-marquee

  • Purpose: Renders a horizontally scrolling marquee of client or affiliation logos.
  • Parameters: items array, basePath, speed, grayscale.
  • Behavior: Validates items, builds image paths, duplicates items for seamless looping, applies grayscale class optionally.
flowchart TD
Start(["Invoke marquee(items, basePath, speed, grayscale)"]) --> CheckItems["items exists and length > 0?"]
CheckItems --> |No| EndEmpty["Render nothing"]
CheckItems --> |Yes| NormalizePath["Ensure basePath ends with '/'"]
NormalizePath --> Loop1["Render items once"]
Loop1 --> Loop2["Render items again for seamless loop"]
Loop2 --> ApplyGrayscale["Apply grayscale class if enabled"]
ApplyGrayscale --> End(["Return marquee HTML"])

Diagram sources

  • [client-marquee.njk](file://src/_includes/macros/client-marquee.njk)

Section sources

  • [client-marquee.njk](file://src/_includes/macros/client-marquee.njk)

Macro: case-study-card

  • Purpose: Renders a single case study entry with optional quote block.
  • Parameters: item object with data fields and content.
  • Behavior: Uses item.data fields for image, category, client, title, and quote; item.content for body; conditionally renders quote box.

Section sources

  • [case-study-card.njk](file://src/_includes/macros/case-study-card.njk)

Macro: testimonial-card

  • Purpose: Renders a testimonial quote with optional case-study variant.
  • Parameters: quote, author, role, isCaseStudy flag.
  • Behavior: Switches between a compact case quote box and a full testimonial card layout.

Section sources

  • [testimonial-card.njk](file://src/_includes/macros/testimonial-card.njk)

Macro: newsletter-signup

  • Purpose: Renders a newsletter subscription form in either compact footer or full variant.
  • Parameters: title, description, buttonText, variant, formId.
  • Behavior: Conditionally renders compact or full layout; constructs ConvertKit form action using site.convertkit_form_id.

Section sources

  • [newsletter-signup.njk](file://src/_includes/macros/newsletter-signup.njk)

Macro: cta-section

  • Purpose: Renders a themed call-to-action section with optional highlighted text.
  • Parameters: title, buttonText, buttonUrl, subtitle, theme, highlightText.
  • Behavior: Applies highlight replacement safely; renders anchor link with provided URL.

Section sources

  • [cta-section.njk](file://src/_includes/macros/cta-section.njk)

Additional Macros Demonstrated

  • team-flip-card: Renders a flip card for team members with front/back content.
  • news-article-card: Renders news cards in carousel or grid/detail variants with optional PDF links.
  • service-capability-card: Renders capability cards with image and link.

Section sources

  • [team-flip-card.njk](file://src/_includes/macros/team-flip-card.njk)
  • [news-article-card.njk](file://src/_includes/macros/news-article-card.njk)
  • [service-capability-card.njk](file://src/_includes/macros/service-capability-card.njk)

Page Templates and Macro Usage

  • index.njk: Declares base layout, imports multiple macros, iterates over collections and data to render carousels, marquee, testimonials, team, news, and CTAs.
  • about.njk: Declares base layout, uses loops and conditionals to render structured content blocks.
  • cases.njk: Declares base layout, imports case-study-card and cta-section, iterates over collections.cases.
  • news.njk: Declares base layout, imports polling-bar, news-article-card, newsletter-signup, and cta-section; includes client-side filtering and animations.
  • media-management.njk: Declares base layout and renders service detail content.
sequenceDiagram
participant Page as "index.njk"
participant Layout as "base.njk"
participant Marquee as "client-marquee.njk"
participant ServiceCard as "service-capability-card.njk"
participant TeamCard as "team-flip-card.njk"
Page->>Layout : Render with layout : base.njk
Page->>Marquee : marquee.marquee(clients.items, ...)
Page->>ServiceCard : serviceCard.card(service)
Page->>TeamCard : teamCard.card(member)
Layout-->>Page : {{ content | safe }} filled

Diagram sources

  • [index.njk](file://src/index.njk)
  • [base.njk](file://src/_includes/layouts/base.njk)
  • [client-marquee.njk](file://src/_includes/macros/client-marquee.njk)
  • [service-capability-card.njk](file://src/_includes/macros/service-capability-card.njk)
  • [team-flip-card.njk](file://src/_includes/macros/team-flip-card.njk)

Section sources

  • [index.njk](file://src/index.njk)
  • [about.njk](file://src/about.njk)
  • [cases.njk](file://src/cases.njk)
  • [news.njk](file://src/news.njk)
  • [media-management.njk](file://src/services/media-management.njk)

Dependency Analysis

  • Pages depend on layouts via front matter declarations.
  • Pages import macros to render reusable components.
  • Macros depend on data passed from collections or data files.
  • Layouts share common assets and navigation across pages.
graph LR
P_index["index.njk"] --> L_base["base.njk"]
P_about["about.njk"] --> L_base
P_cases["cases.njk"] --> L_base
P_news["news.njk"] --> L_base
P_service["services/media-management.njk"] --> L_base
P_index -. imports .-> M_marquee["client-marquee.njk"]
P_index -. imports .-> M_service_card["service-capability-card.njk"]
P_index -. imports .-> M_team["team-flip-card.njk"]
P_index -. imports .-> M_news_card["news-article-card.njk"]
P_index -. imports .-> M_testimonial["testimonial-card.njk"]
P_index -. imports .-> M_cta["cta-section.njk"]
P_cases -. imports .-> M_case["case-study-card.njk"]
P_cases -. imports .-> M_cta
P_news -. imports .-> M_news_card
P_news -. imports .-> M_newsletter["newsletter-signup.njk"]
P_news -. imports .-> M_cta

Diagram sources

  • [index.njk](file://src/index.njk)
  • [about.njk](file://src/about.njk)
  • [cases.njk](file://src/cases.njk)
  • [news.njk](file://src/news.njk)
  • [media-management.njk](file://src/services/media-management.njk)
  • [base.njk](file://src/_includes/layouts/base.njk)
  • [client-marquee.njk](file://src/_includes/macros/client-marquee.njk)
  • [service-capability-card.njk](file://src/_includes/macros/service-capability-card.njk)
  • [team-flip-card.njk](file://src/_includes/macros/team-flip-card.njk)
  • [news-article-card.njk](file://src/_includes/macros/news-article-card.njk)
  • [testimonial-card.njk](file://src/_includes/macros/testimonial-card.njk)
  • [newsletter-signup.njk](file://src/_includes/macros/newsletter-signup.njk)
  • [case-study-card.njk](file://src/_includes/macros/case-study-card.njk)
  • [cta-section.njk](file://src/_includes/macros/cta-section.njk)

Section sources

  • [index.njk](file://src/index.njk)
  • [about.njk](file://src/about.njk)
  • [cases.njk](file://src/cases.njk)
  • [news.njk](file://src/news.njk)
  • [media-management.njk](file://src/services/media-management.njk)
  • [base.njk](file://src/_includes/layouts/base.njk)

Performance Considerations

  • Prefer importing macros once per page and passing minimal data to reduce re-renders.
  • Use loops judiciously; avoid heavy computations inside macros.
  • Leverage Eleventy’s collection iteration to pre-process data where possible.
  • Keep layout logic generic to minimize duplication and improve maintainability.

Troubleshooting Guide

Common issues and resolutions:

  • Macro not rendering: Verify import path and macro name match the import alias.
  • Empty or missing content: Confirm front matter declares a valid layout and that collections/data keys exist.
  • Incorrect filters: Ensure filters like safe, replace, and dateFormat are applied correctly and only on appropriate values.
  • Navigation highlighting: Check active_nav values against page.url comparisons in the base layout.
  • Layout conflicts: When using knowledge.njk, ensure it still extends base.njk so shared assets remain consistent.

Section sources

  • [base.njk](file://src/_includes/layouts/base.njk)
  • [knowledge.njk](file://src/_includes/layouts/knowledge.njk)
  • [index.njk](file://src/index.njk)
  • [news.njk](file://src/news.njk)

Conclusion

The Nunjucks/Eleventy setup uses a clean separation of concerns: layouts define the shell, pages provide content, and macros encapsulate reusable components. By leveraging front matter, imports, filters, and loops, the system scales efficiently while remaining maintainable. Following the patterns documented here enables consistent extension and debugging.

Appendices

Practical Examples

  • Creating a new macro

    • Define a macro in a new file under src/_includes/macros/, using parameters and defaults as needed.
    • Import the macro in the page template and pass data from collections or data files.
    • Example reference paths:
      • [newsletter-signup.njk](file://src/_includes/macros/newsletter-signup.njk)
      • [index.njk](file://src/index.njk)
  • Extending a layout

    • Create a new layout that sets layout: base.njk in front matter to inherit the base shell.
    • Add page-specific sections while keeping the main structure intact.
    • Example reference paths:
      • [knowledge.njk](file://src/_includes/layouts/knowledge.njk)
      • [base.njk](file://src/_includes/layouts/base.njk)
  • Implementing template inheritance

    • Declare layout: base.njk in front matter for any page that needs the base shell.
    • Use {{ content | safe }} in the layout to inject page content.
    • Example reference paths:
      • [index.njk](file://src/index.njk)
      • [base.njk](file://src/_includes/layouts/base.njk)
  • Template syntax highlights

    • Variable interpolation: {{ variable }}
    • Filters: {{ variable | filter }}
    • Conditionals: {% if ... %} ... {% endif %}
    • Loops: {% for item in items %} ... {% endfor %}
    • Imports: {% import "macros/..." as alias %}
    • Example reference paths:
      • [index.njk](file://src/index.njk)
      • [about.njk](file://src/about.njk)
      • [news.njk](file://src/news.njk)
  • Debugging techniques

    • Temporarily wrap content with comments or placeholders to isolate rendering issues.
    • Validate front matter keys and collection names.
    • Use browser dev tools to inspect generated HTML and confirm macro output.
    • Example reference paths:
      • [base.njk](file://src/_includes/layouts/base.njk)
      • [index.njk](file://src/index.njk)